/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using QUT.Bio.Util;

using QUT.Bio.Graphs;
using QUT.Bio.SilverMap.ObjectModel;
using DataGridCheckBoxColumn = QUT.Bio.Util.DataGridCheckBoxColumn;
using DataGridTextColumn = QUT.Bio.Util.DataGridTextColumn;

#if USING_TAGS
using TagModule;
#endif

// TODO: Insert Silverlight workaround for absence of double click.
// TODO: Finish off the alignment displays.

namespace QUT.Bio.SilverMap {

	/// <summary>
	/// Sequence property panel displays the proeprties of a specific sequence.
	/// </summary>

	public partial class SequencePropertyPanel : UserControl {

		private ViewModel model;
		private ILinearDomain sequence;
		private Action<SequencePropertyPanel, ILinearDomain, IEnumerable<Xref>> xrefAction;

		#region Constructor
		/// <summary>
		/// Initialise the SequqncePropertyPanel, setting xref action to the default operation.
		/// </summary>

		public SequencePropertyPanel () {
			InitializeComponent();

			xrefAction = DefaultXrefAction;
		} 
		#endregion

		#region Method: DefaultXrefAction
		/// <summary>
		/// Default callback for the "show details" button. It will be overwritten by a
		/// non-null xrefAction supplied to Initialize. By default, we display a "not implemented message".
		/// </summary>
		/// <param name="p">Ignored.</param>
		/// <param name="s">Ignored.</param>
		/// <param name="x">Ignored.</param>

		private void DefaultXrefAction ( SequencePropertyPanel p, ILinearDomain s, IEnumerable<Xref> x ) {
			Alert.Show( "This operation is not supported in the current version." );
		} 
		#endregion

		#region Method: Initialize
		/// <summary>
		/// Initialise a new SequencePropertyPanel. This method must be called on purpose
		/// to perform initialisation that is impossible in a parameterless constructor.
		/// </summary>
		/// <param name="model">The viewmodel for the client application.</param>
		/// <param name="xrefAction">A callback function (which may be null) that will be executed when the cross references are double clicked.</param>

		public void Initialize (
			ViewModel model,
			Action<SequencePropertyPanel, ILinearDomain, IEnumerable<Xref>> xrefAction
		) {
			this.model = model;

			if ( xrefAction != null ) {
				this.xrefAction = xrefAction;
			}
		} 
		#endregion

		#region Property: Sequence
		/// <summary>
		/// Get or set the sequence being displayed by this SequencePropertyPanel.
		/// </summary>

		public ILinearDomain Sequence {
			get {
				return sequence;
			}
			set {
				this.sequence = value;

				if ( value == null ) {
					overlay.Visibility = Visibility.Visible;
				}
				else {
					overlay.Visibility = Visibility.Collapsed;
				}

				showDetails.IsEnabled = false;

				labelField.Text = sequence.Label;
				descriptionField.Text = sequence.Name;

				#region Update the descrptionGrid
				{
					List<FrameworkElement> childrenToRemove = new List<FrameworkElement>();

					foreach ( FrameworkElement element in descriptionGrid.Children ) {
						if ( element.GetRow() >= 2 ) {
							childrenToRemove.Add( element );
						}
					}

					foreach ( FrameworkElement element in childrenToRemove ) {
						descriptionGrid.Children.Remove( element );
					}

					for ( int i = descriptionGrid.RowDefinitions.Count - 1; i >= 2; i-- ) {
						descriptionGrid.RowDefinitions.RemoveAt( i );
					}

					ObjectWrapper sequenceWrapper = new ObjectWrapper( sequence );
					RowDefinitionCollection rows = descriptionGrid.RowDefinitions;

					foreach ( PropertyInfo property in sequenceWrapper.DisplayedProperties ) {
						TextBlock nameField = new TextBlock {
							Style = (Style) Resources["Head"],
							Text = property.Name
						};

						object propertyValue = sequenceWrapper[property.Name];

						TextBlock valueField = new TextBlock {
							Style = (Style) Resources["Text"],
							Text = propertyValue == null ? "n/a" : propertyValue.ToString()
						};

						valueField.SetColumn( 1 );

						descriptionGrid.AddRow( nameField, valueField );
					}
				}
				#endregion

				#region Display the Xrefs.
				IEnumerable<Xref> xrefs = from Xref x in sequence.Xref
										  where x.Database == "GI"
										  select x;
				Xref xref = xrefs.FirstOrDefault();

				if ( xref != null ) {
					// This assumes that all items to be displayed have the same list of
					// displayed properties, and that we have DB and Id in all cases.
					ObjectWrapper wrapper = new ObjectWrapper( xref );

					for ( int i = xrefGrid.Columns.Count - 1; i >= 2; i-- ) {
						xrefGrid.Columns.Remove( xrefGrid.Columns[i] );
					}

					foreach ( PropertyInfo property in wrapper.DisplayedProperties ) {
						if ( typeof( bool ).IsAssignableFrom( property.PropertyType ) ) {
							DataGridCheckBoxColumn c = new DataGridCheckBoxColumn();
							c.Binding = new Binding {
								Mode = property.GetSetMethod() == null ? BindingMode.OneWay : BindingMode.TwoWay,
								Path = new PropertyPath( property.Name )
							};
							c.CanUserReorder = true;
							c.CanUserResize = true;
							c.CanUserSort = true;
							c.Header = property.Name;
							xrefGrid.Columns.Add( c );
						}
						else {
							DataGridTextColumn c = new DataGridTextColumn();
							c.Binding = new Binding {
								Mode = BindingMode.OneWay,
								Path = new PropertyPath( property.Name )
							};
							c.CanUserReorder = true;
							c.CanUserResize = true;
							c.CanUserSort = true;
							c.Header = property.Name;
							xrefGrid.Columns.Add( c );
						}
					}

					xrefGrid.ItemsSource = xrefs;
					xrefContainer.Visibility = Visibility.Visible;
					xrefRow.Height = new GridLength( 1, GridUnitType.Star );
					xrefGrid.SelectedItem = xref;
				}
				else {
					xrefContainer.Visibility = Visibility.Collapsed;
					xrefRow.Height = new GridLength( 0 );
				}

				#endregion

				if ( xrefAction != null ) {
					showDetails.Visibility = Visibility.Visible;
				}

				#region Add hsp panels for each hit between the current reference gene and the current sequence
				hspContainer.Children.Clear();

				foreach ( Hit h in model.DataProducer.FeatureCollection.Hits ) {
					if ( h.QueryFeature.ContainingSequence.Equals( model.ReferenceSequence )
						&& h.HitFeature.ContainingSequence.Equals( sequence )
					) {
						HspPanel hspPanel = new HspPanel {
							Hit = h,
							Margin = new Thickness( 15, 0, 0, 10 ),
							HorizontalAlignment = HorizontalAlignment.Stretch
						};
						hspContainer.Children.Add( hspPanel );
					}
				}
				#endregion
			}
		} 
		#endregion

		#region Method: ShowDetails
		/// <summary>
		/// Event listener for the "Show details" button. Calls the xref action callback.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void ShowDetails ( object sender, RoutedEventArgs e ) {
			if ( xrefAction != null ) {
				xrefAction( this, sequence, from object xref in xrefGrid.SelectedItems
											select (Xref) xref );
			}
		} 
		#endregion

		#region Method: XrefGridSelectionChanged.
		/// <summary>
		/// Listener for selection changes in the data grid: sets the "show details" button
		/// active if an item is selected.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void XrefGridSelectionChanged ( object sender, SelectionChangedEventArgs e ) {
			showDetails.IsEnabled = xrefGrid.SelectedItems != null;
		} 
		#endregion
	}
}
